Dart eval:exportGraph 概念
介绍
Compiler.dart 的 _resolveImportsAndExports 负责对 Library 的导入导出关系进行分析,其中包含一个 exportGraph,本文梳理 exportGraph 的逻辑。
在 Compiler.dart 的 _resolveImportsAndExports 中,exportGraph 创建方式如下:
final exportGraph = DirectedGraph<Uri>({
for (final l in libraries)
l.uri: {
for (final export in l.exports) Uri.parse(export.uri.stringValue!)
}
});
实例
找到一个与 export 相关的测试用例:'Export chains',位于 test\lib_composition_test.dart。
该用例中声明了如下源码:
main.dart:
import 'package:example/b1.dart';
int main() {
final b = ClassB();
return b.number();
}
b1.dart:
library b1;
export 'package:example/b2.dart' show ClassB;
b2.dart:
export 'package:example/b3.dart';
b3.dart:
class ClassB {
ClassB();
int number() { return 8; }
}
他们之间的相互关系如下:
- main.dart 文件中:
- 通过 import 关键字将 b1.dart 引入
- 并调用了 b1.dart 中导出的 ClassB 类
- b1.dart 文件中:
- 通过 export 关键字将 b2.dart 中的 ClassB 类导出,供其他文件调用
- b2.dart 文件中:
- 通过 export 关键字将 b3.dart 中的内容导出
- b3.dart 文件中:
- 定义了一个 ClassB 类
- 包含一个构造函数和一个返回整型数的 number() 方法
exportGraph 运行时效果
运行时看 exportGraph 的 _edges 属性,包含 7 个元素,伪代码如下:
{
"dart:core": {},
"dart:math": {},
"dart:async": {},
"package:example/main.dart": {},
"package:example/b1.dart": {
"package:example/b2.dart"
},
"package:example/b2": {
"package:example/b3.dart"
},
"package:example/b3.dart": {}
}
与代码对比,终于理解了 exportGraph 就是每个文件对外的 export,并且是能够串起来的(图)。
exportGraph.crawler.tree
继续来到下面逻辑:
for (final import in [
...l.imports.map((e) => _Import(
Uri.parse(e.uri.stringValue!), e.prefix?.name, e.combinators)),
if (!isDartCore) _Import(dartCoreUri, null)
]) {
final tree = exportGraph.crawler.tree(import.uri);
final importedLibs = [...tree.expand((e) => e), import.uri]
.map((e) =>
uriMap[e] ??
(throw CompileError(
"Cannot find import '$e' (while parsing '${l.uri}')")))
.toSet();
final importedExports =
importedLibs.map((e) => e.exports).expand((e) => e);
注意,这部分代码套在 for (final l in libraries) {
内,当 l 为 main.dart 时:
tree 为,列表:
[
{"package:example/b2.dart"},
{"package:example/b2.dart", "package:example/b3.dart"}
]
即以 main.dart 作为根的引用关系链。 importedLibs 为,集合:
{
Library("package:example/b2.dart"),
Library("package:example/b3.dart"),
Library("package:example/b1.dart"),
}
把 main 中的 import(b1)也加上了。
importedExports 为类型为 ExportDirective 的 Iterator,把 importedLibs 中所有的 export 都展开了。
exportsPerUri 为 <Uri, List<ExportDirective>>{}
:
{
"package:example/b3.dart": [
ExportDirectiveImpl (export 'package:example/b3.dart')
],
"package:example/b2.dart": [
ExportDirectiveImpl (export 'package:example/b2.dart' show ClassB;)
]
}
visibleDeclarations:
mappedVisibleDeclarations:
result,Map:
{
Library("dart:core"): {
"print": DeclarationOrPrefix,
"Future": DeclarationOrPrefix,
"Duration": DeclarationOrPrefix,
"DateTime": DeclarationOrPrefix,
},
Library("dart:math"): {
"Point": DeclarationOrPrefix,
"print": DeclarationOrPrefix,
"Future": DeclarationOrPrefix,
"Duration": DeclarationOrPrefix,
"DateTime": DeclarationOrPrefix,
},
Library("dart:async"): {
"Completer": DeclarationOrPrefix,
"print": DeclarationOrPrefix,
"Future": DeclarationOrPrefix,
"Duration": DeclarationOrPrefix,
"DateTime": DeclarationOrPrefix,
},
Library("package:example/main.dart"): {
"main": DeclarationOrPrefix,
"ClassB": DeclarationOrPrefix,
"ClassB.": DeclarationOrPrefix,
"print": DeclarationOrPrefix,
"Future": DeclarationOrPrefix,
"Duration": DeclarationOrPrefix,
"DateTime": DeclarationOrPrefix,
},
Library("package:example/b1.dart"): {
"print": DeclarationOrPrefix,
"Future": DeclarationOrPrefix,
"Duration": DeclarationOrPrefix,
"DateTime": DeclarationOrPrefix,
},
Library("package:example/b2.dart"): {
"print": DeclarationOrPrefix,
"Future": DeclarationOrPrefix,
"Duration": DeclarationOrPrefix,
"DateTime": DeclarationOrPrefix,
},
Library("package:example/b3.dart"): {
"ClassB": DeclarationOrPrefix,
"ClassB.": DeclarationOrPrefix,
"print": DeclarationOrPrefix,
"Future": DeclarationOrPrefix,
"Duration": DeclarationOrPrefix,
"DateTime": DeclarationOrPrefix,
},
}